﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Net.Sockets;
using System.Net;

using System.Threading;

namespace MyClassSocket
{
    class CServidor
    {
        //start
        public CServidor(int puerto)
        {
            IPHostEntry hostInfo = Dns.Resolve(Dns.GetHostName());
            IPAddress direccionIP = hostInfo.AddressList[0];
            //IPAddress direccionIP = IPAddress.Parse("25.205.167.88");
            localEP = new IPEndPoint(direccionIP, puerto);            
            sockServer = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        
            conexionMaxima = 5;
            conexionMinima = 2;

            sockCliente = new Socket[conexionMaxima];
            atencionCliente = new Thread[conexionMaxima];
            paq = new byte[conexionMaxima][];
            //hiloEscucha = new Thread[conexionMaxima];
        }

        //Runnin
        public void Run()
        {
            //acepta conexiones entrantes o nuevas
            try 
	        {	        
		        sockServer.Bind(localEP);
                sockServer.Listen(conexionMaxima);

                conexionesEstablecidas = 0;

                string[] puertoEspecial;

                IPHostEntry hostInfo = Dns.Resolve(Dns.GetHostName());
                string IPString = hostInfo.AddressList[0].ToString();

                Console.WriteLine("Direccion IP Del Servidor: " + IPString);
                Console.WriteLine("Esperando Conexion...");

                while (conexionesEstablecidas < conexionMaxima)
                {
                    sockCliente[conexionesEstablecidas] = sockServer.Accept();
                    paq[conexionesEstablecidas] = new byte[1024];

                    char[] separate = {':'};
                    puertoEspecial = sockCliente[conexionesEstablecidas].RemoteEndPoint.ToString().Split(separate);

                    sockCliente[conexionesEstablecidas].Receive(paq[conexionesEstablecidas]);
                    Paq_Generic = (CPaq_Genric) CSRepositor.Desempaquetar(paq[conexionesEstablecidas]);

                    if (Paq_Generic.peticion == "Conectar")
                    {
                        Paq_Asig.ID = conexionesEstablecidas;
                        Paq_Asig.mensage = "Aceptado";
                        Paq_Asig.newPort = puertoEspecial[1];

                        paq[conexionesEstablecidas] = CSRepositor.Empaquetar((object)Paq_Asig);
                        sockCliente[conexionesEstablecidas].Send(paq[conexionesEstablecidas]);
                        

                        //despues de cada send vacioamos el paq
                        paq[conexionesEstablecidas] = null;

                        Console.WriteLine("Conexion Establecida Con ID: " + conexionesEstablecidas);
                        Console.WriteLine("     IP de ID : "+ conexionesEstablecidas +" -  " + sockCliente[conexionesEstablecidas].RemoteEndPoint.ToString());

                        conexionesEstablecidas++;
                    }
                }
                Console.WriteLine("-*-* ALCANZADO LIMITE DE CONEXIONES *-*-");

	        }
	        catch (Exception e)
	        {
		        string lala = e.ToString();
                Console.WriteLine(lala);
	        }
        }

        //Listen
        public void listenToClient()
        {
            try
            {      
                for (int i = 0; i < conexionesEstablecidas; i++)
                {
                    //Array.Clear(paq[i], 0, 1024);
                    //vaciamos todo antes de recibir
                    paq[i] = null;
                    paq[i] = new byte[1024];
                    sockCliente[i].Receive(paq[i]);
                }
            }            
            catch (Exception e)
            {
                string lala = e.ToString();
                Console.WriteLine(lala);
            }
        }

        //Datos
        
        //Datos para etablecer la conexion con el socket principal
        IPEndPoint localEP;
        Socket sockServer;
        
        //por cada cliente se le deriva un socket que escuchara solo a ese unico cliente en un hilo propio
        public Socket[] sockCliente;
        Thread[] atencionCliente;

        //paquete de datos estati, seran tantos como cliente por hilo ayan
        //esto es por que un hilo comparte info dentro el mimso namespace y la manera mas facil es usando un miembro estatico
        public byte[][] paq;
            
        //seteo las conexion
        //Maxima: cantidad de clientes que podra manejar
        int conexionMaxima, conexionMinima;
        public int conexionesEstablecidas;

        //Receptor de Paq
        CPaq_Genric Paq_Generic = new CPaq_Genric();
        CPaq_Asignacion Paq_Asig = new CPaq_Asignacion();
    }
}
